package com.hongbo.idscanner

import android.content.Context
import android.content.Intent
import android.device.DeviceManager
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.hongbo.idscanner.IdScan.DELAY_TIME
import com.hongbo.idscanner.IdScan.KEY_DEVICE_IMG_INFO
import com.hongbo.idscanner.IdScan.KEY_DEVICE_INFO
import com.hongbo.idscanner.IdScan.KEY_ID_SCAN_INFO
import com.hongbo.idscanner.IdScan.SCAN_DEVICE_ID_FILTER
import com.hongbo.idscanner.IdScan.SCAN_DEVICE_ID_IMG_FILTER
import com.hongbo.idscanner.IdScan.SCAN_FILTER
import com.hongbo.utils.Player
import com.huashi.otg.sdk.HSIDCardInfo
import com.huashi.otg.sdk.HandlerMsg
import com.huashi.otg.sdk.HsSerialPortSDK
import com.zhb.tools.ZLog
import kotlinx.coroutines.*

/**
 * ID读卡器
 * Created by HongboZhao on 2021/1/7.
 */

@Suppress("DEPRECATED_IDENTITY_EQUALS")
class IdScanHelper(private val appContext: Context) {

    @Volatile
    var com = false

    @Volatile
    var stop = true

    @Volatile
    var check = false //开始检测

    @Volatile
    var isContinued = false //是否连续读卡模式

    @Volatile
    var isSaveAllPic = false //是否保存所有图像

    private val mDeviceManager: DeviceManager by lazy { DeviceManager() }
    private val comApi: HsSerialPortSDK by lazy {
        HsSerialPortSDK(
                appContext,
                appContext.filesDir.absolutePath
        )
    }

    fun startAuto(isAuto: Boolean) {
        CoroutineScope(Dispatchers.IO).launch {
            if (isAuto) {
                if (!isContinued) {
                    isContinued = true
                    open()
                }
            } else {
                if (isContinued) {
                    isContinued = false
                    close()
                }
            }
        }
    }

    /**
     * 开始刷卡
     */
    fun open() {
        if (!check) {
            return
        }
        CoroutineScope(Dispatchers.IO).launch {
            val connStatus = async {
                try {
                    if (!com) {
                        launch(Dispatchers.Main) {
                            try {
                                mDeviceManager.enableNfc(false)
                            } catch (e: Exception) {
                                ZLog.e("enableNfc error", e)
                            }
                        }
                        delay(500)
                        comApi.PowerOn()
                        delay(500)
                        comConn()
                    } else {
                        true
                    }
                } catch (e: Exception) {
                    ZLog.e("open", e)
                    false
                }
            }
            if (connStatus.await()) {
                sendDeviceResult("请放置身份证件")
                if (isContinued) {
                    cpuThread()
                } else {
                    comRead()
                }
            } else {
                val closeTask = async { close(true) }
                val openTask = async { open() }
                closeTask.await()
                openTask.await()
            }
        }
    }

    /**
     * 启动ID扫描后台工作
     */
    fun start(context: Context) {
        //使用Worker进行身份证读取
        check = true
        val request = OneTimeWorkRequest.Builder(ScanWorker::class.java).build()
        WorkManager.getInstance(context).enqueue(request)
    }

    fun close() {
        close(false)
    }

    /**
     * 关闭刷卡
     */
    private fun close(isCom: Boolean) {
        check = isCom
        CoroutineScope(Dispatchers.IO).launch {
            if (com) {
                try {
                    val closeStatus = async {
                        try {
                            comApi.close() == 0
                        } catch (e: Exception) {
                            ZLog.e("close-close", e)
                            false
                        }
                    }
                    if (closeStatus.await()) {
                        com = isCom
                        Log.d("=======close=====>${com},${stop},${check}")
                        comApi.PowerDown()
                        delay(DELAY_TIME)
                        launch(Dispatchers.Main) {
                            try {
                                mDeviceManager.enableNfc(true)
                            } catch (e: Exception) {
                                ZLog.e("close-PowerDown", e)
                            }
                        }
                        delay(DELAY_TIME)
                    }
                } catch (e: Exception) {
                    ZLog.e("close", e)
                }
            }
        }
    }

    //连接
    private fun comConn(): Boolean {
        sendDeviceResult("读卡设备准备中")
        // 因为第一次需要点击授权，所以第一次点击时候的返回是-1所以我利用了广播接受到授权后用handler发送消息
        val ret: Int = comApi.init("/dev/ttyHSL0", 115200, 0)
        return if (ret == 0) {
            com = true
            Log.d("=======comConn=====>${com},${stop},${check}")
            true
        } else {
            false
        }
    }

    /**
     * 点击读卡
     */
    fun comRead() {
        if (!com) {
            sendDeviceResult("连接中")
            //未连接状态进行设备连接
            check = true
            //非自动读卡模式
            isContinued = false
            open()
            return
        }
        if (comApi.Authenticate(1000) !== 0) {
            sendDeviceResult("卡认证失败")
            return
        }
        //连续读卡模式下不能使用单独读卡
        if (isContinued) {
            return
        }
        val ici = HSIDCardInfo()
        if (comApi.Read_Card(ici, 2300) === 0) {
            handleMessage(HandlerMsg.ComREAD_SUCCESS, ici)
        } else {
            sendDeviceResult("读卡失败")
            return
        }
    }

    /**
     * 连续读卡
     */
    private fun cpuThread() {
        CoroutineScope(Dispatchers.IO).launch {
            stop = false
            var eor: Int
            while (com && check && isContinued) {
                Log.d("=======While=====>${com},${stop},${check}")
                if (!com) {
                    break
                }
                eor = comApi.Authenticate(1000)
                if (eor == 0) {
                    val ici = HSIDCardInfo()
                    if (comApi.Read_Card(ici, 2300) === 0) {
                        handleMessage(HandlerMsg.ComREAD_SUCCESS, ici)
                    }
                } else {
                    if (eor == 3) {
                        // 接收超时，默认为被静电打死,重新进行上下电
                        handleMessage(100, "断线重连中......")
                        val downTask = async {
                            comApi.PowerDown()
                            delay(DELAY_TIME)
                        }
                        val onTask = async {
                            comApi.PowerOn()
                            delay(DELAY_TIME)
                        }
                        downTask.await()
                        onTask.await()
                    } else {
                        handleMessage(HandlerMsg.READ_ERROR, null)
                    }
                }
                delay(600)
            }
            stop = true
            isContinued = false
            handleMessage(HandlerMsg.AutoReadStop, "")
        }
    }

    companion object {
        var context: Context? = null
        var isDebug = true

        val ins: IdScanHelper? by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            var helper: IdScanHelper? = null
            if (context != null) {
                helper = IdScanHelper(context!!)
            }
            helper
        }
    }

    private fun handleMessage(status: Int, obj: Any?) {
        runBlocking {
            launch(Dispatchers.IO) {
                if (status == 99 || status == 100) {
                    Log.d(obj as String)
                }
                // 第一次授权时候的判断是利用handler判断，授权过后就不用这个判断了
                if (status == HandlerMsg.CONNECT_SUCCESS) {
                    sendDeviceResult("连接成功")
                }
                if (status == HandlerMsg.CONNECT_ERROR) {
                    sendDeviceResult("连接失败")
                }
                if (status == HandlerMsg.READ_ERROR) {
                    sendDeviceResult("卡认证失败")
                }
                if (status == HandlerMsg.M1Read_SUCCESS) {
                    sendDeviceResult(obj as String)
                }
                if (status == HandlerMsg.AutoReadStop) {
                    sendDeviceResult("自动读卡停止")
                }
                if (status == HandlerMsg.ComREAD_SUCCESS) {
                    sendDeviceResult("读卡成功")

                    val ic: HSIDCardInfo = obj as HSIDCardInfo
                    parseImage(ic) //解码图像

                    // 播放语音文件
                    Player.playMp3()

                    //解析打印日志，可删除
                    if (isDebug) {
                        IdScanResult.doResult(ic)
                    }

                    //发送广播
                    sendResult(ic)
                }
            }
        }
    }

    /**
     * 解码头像和身份证正反面
     */
    private fun parseImage(ic: HSIDCardInfo) {
        try {
            val bmpBuf = ByteArray(102 * 126 * 3 + 54 + 126 * 2) // 照片头像bmp数据
            val ret: Int = comApi.unpack(ic.getwltdata(), bmpBuf, IdScanResult.headerImgPath)
            if (ret == 1) {
                Log.d("头像解码成功")
                if (isSaveAllPic) {
                    IdScanResult.parseImageBg(ic, bmpBuf)
                }
                //通知图像保存成功
                sendImgResult(bmpBuf)
            } else {
                Log.d("头像解码失败")
            }
        } catch (e: Exception) {
            Log.d("头像解码失败")
        }
    }

    /**
     * 发送结果广播
     */
    private fun sendResult(ic: HSIDCardInfo) {
        val intent = Intent(SCAN_FILTER)
        intent.putExtra(KEY_ID_SCAN_INFO, IDCardInfo().parse(ic))
        context!!.sendBroadcast(intent)
    }

    /**
     * 发送设备状态广播
     * 获取头像，BitmapFactory.decodeByteArray(bmpBuf, 0, bmpBuf.size)
     */
    private fun sendDeviceResult(tips: String) {
        Log.d(tips)
        val intent = Intent(SCAN_DEVICE_ID_FILTER)
        intent.putExtra(KEY_DEVICE_INFO, tips)
        context!!.sendBroadcast(intent)
    }

    /**
     * 发送身份证图片广播
     */
    private fun sendImgResult(bmpBuf: ByteArray) {
        val intent = Intent(SCAN_DEVICE_ID_IMG_FILTER)
        intent.putExtra(KEY_DEVICE_IMG_INFO, bmpBuf)
        context!!.sendBroadcast(intent)
    }
}